#pragma once
#include <mysql/mysql.h>
#include <string>
#include <vector>
#include <cstring>
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
#include <mutex>

namespace ns_user_model
{
    // 用户数据结构
    struct User
    {
        int user_id; // 用户id,唯一标识用户
        std::string username;
        std::string password_hash;
        std::string email;
        std::string role;   // "user" 或 "admin"
        int total_submit;   // 总提交次数
        int accepted_count; // AC次数
        time_t create_time;
        time_t last_login;
    };

    // 提交记录结构（用于查询用户历史）
    struct Submission
    {
        int submission_id;
        int user_id;
        std::string question_number;
        int status; // 0表示未通过,1表示AC
        std::string submit_time;
    };

    // 最基本的用户注册和登陆验证功能
    // 额外附加的:用户提交数,通过数——均在用户表中,可以以此排序
    // 用户表外的submission表,额外记录用户的提交记录
    class UserModel
    {
    private:
        // thread_local static MYSQL *mysql_;//非submissions的mysql连接
        // thread_local static MYSQL *mysql_submissions_;//submissions的mysql连接
        // SHA256密码哈希 - 简单安全的密码加密
        std::string HashPassword(const std::string &password)
        {
            unsigned char hash[SHA256_DIGEST_LENGTH];                         // 用来存储密码哈希之后的32字节结果
            SHA256((unsigned char *)password.c_str(), password.size(), hash); // 进行SHA256哈希加密

            // 转换为16进制字符串
            std::stringstream ss;
            for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
            {
                // 将32字节中每一个字节转换为两个16进制数,默认右对齐,不足补0--->64位16进制的哈希结果存储到ss中
                ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
            }
            return ss.str();
        }
        MYSQL *InitConnection()
        {
            // 初始化MySQL连接
            MYSQL *mysql_ = mysql_init(nullptr);
            if (mysql_ == nullptr)
            {
                return mysql_;
            }

            // 连接数据库
            if (mysql_real_connect(mysql_, host_.c_str(), user_.c_str(),
                                   passwd_.c_str(), db_.c_str(), port_, nullptr, 0) == nullptr)
            {
                mysql_close(mysql_);
                mysql_ = nullptr;
                return mysql_;
            }

            // 设置字符集为UTF8
            mysql_set_character_set(mysql_, "utf8mb4");
            return mysql_;
        }
    const std::string host_ = "127.0.0.1";
    const std::string user_ = "oj_client";
    const std::string passwd_ = "Wunuofan123@%";
    const std::string db_ = "oj";
    const int port_ = 3306;

    public:
        UserModel()
        {
            // // 初始化MySQL连接
            // mysql_ = mysql_init(nullptr);
            // if (mysql_ == nullptr)
            // {
            //     return;
            // }

            // // 连接数据库
            // if (mysql_real_connect(mysql_, host.c_str(), user.c_str(),
            //                        passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
            // {
            //     mysql_close(mysql_);
            //     mysql_ = nullptr;
            // }

            // // 设置字符集为UTF8
            // mysql_set_character_set(mysql_, "utf8mb4");
        }

        // 释放MYSQL*类型成员
        ~UserModel()
        {
            // if (mysql_)
            // {
            //     mysql_close(mysql_);
            // }
        }

        // 用户注册 - 插入新用户
        // 返回值：true-成功 false-失败（用户名已存在或数据库错误）
        bool RegisterUser(const std::string &username,
                          const std::string &password,
                          const std::string &email)
        {
            MYSQL *mysql_ = InitConnection();
            if (!mysql_)
                return false;

            // 密码加密
            std::string password_hash = HashPassword(password);

            // SQL插入语句 - 使用IGNORE避免重复用户名导致程序崩溃
            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "INSERT INTO users (username, password_hash, email, role) "
                     "VALUES ('%s', '%s', '%s', 'user')",
                     username.c_str(), password_hash.c_str(), email.c_str());

            // 执行SQL - 如果用户名重复，会返回失败
            if (mysql_query(mysql_, sql) != 0)
            {
                mysql_close(mysql_);
                return false; // 插入失败，可能是用户名重复
            }
            mysql_close(mysql_);
            return true;
        }

        // 用户登录验证 - 验证用户名和密码
        // 返回值：true-验证成功 false-用户名或密码错误
        bool VerifyUser(const std::string &username,
                        const std::string &password,
                        User *user)
        {
            MYSQL *mysql_ = InitConnection();
            if (!mysql_)
                return false;

            // 密码加密后进行比对
            std::string password_hash = HashPassword(password);

            // SQL查询语句
            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "SELECT user_id, username, email, role, total_submit, "
                     "accepted_count, UNIX_TIMESTAMP(create_time), UNIX_TIMESTAMP(last_login) "
                     "FROM users WHERE username='%s' AND password_hash='%s'",
                     username.c_str(), password_hash.c_str());

            // 执行查询
            if (mysql_query(mysql_, sql) != 0)
            {
                mysql_close(mysql_);
                return false;
            }

            // 获取结果:一次性获取并存储所有结果
            MYSQL_RES *result = mysql_store_result(mysql_);
            if (result == nullptr)
            {
                mysql_close(mysql_);
                return false;
            }

            // 检查是否有匹配的用户
            MYSQL_ROW row = mysql_fetch_row(result);
            if (row == nullptr)
            {
                mysql_free_result(result);
                mysql_close(mysql_);
                return false; // 用户名或密码错误
            }

            // 填充用户信息
            user->user_id = atoi(row[0]);
            user->username = row[1];
            user->email = row[2] ? row[2] : "";
            user->role = row[3];
            user->total_submit = atoi(row[4]);
            user->accepted_count = atoi(row[5]);
            user->create_time = atol(row[6]);
            user->last_login = row[7] ? atol(row[7]) : 0;

            mysql_free_result(result);

            // 更新最后登录时间
            snprintf(sql, sizeof(sql),
                     "UPDATE users SET last_login=NOW() WHERE user_id=%d",
                     user->user_id);
            mysql_query(mysql_, sql);
            mysql_close(mysql_);
            return true;
        }

        // 根据用户ID获取用户信息
        bool GetUserById(int user_id, User *user)
        {
            MYSQL *mysql_ = InitConnection();
            if (!mysql_)
                return false;
            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "SELECT user_id, username, email, role, total_submit, "
                     "accepted_count, UNIX_TIMESTAMP(create_time), UNIX_TIMESTAMP(last_login) "
                     "FROM users WHERE user_id=%d",
                     user_id);
            if (mysql_query(mysql_, sql) != 0)
            {
                mysql_close(mysql_);
                return false;
            }

            MYSQL_RES *result = mysql_store_result(mysql_);
            if (result == nullptr)
            {
                mysql_close(mysql_);
                return false;
            }

            // int rows = mysql_num_rows(result);无意义的,因为正确情况下,只会有一行数据
            // int cols = mysql_num_fields(result);
            MYSQL_ROW row = mysql_fetch_row(result);
            if (row == nullptr)
            {
                mysql_free_result(result);
                mysql_close(mysql_);

                return false;
            }

            // struct user和数据表中的顺序相照应
            user->user_id = atoi(row[0]);
            user->username = row[1];
            user->email = row[2] ? row[2] : "";
            user->role = row[3];
            user->total_submit = atoi(row[4]);
            user->accepted_count = atoi(row[5]);
            user->create_time = atol(row[6]);
            user->last_login = row[7] ? atol(row[7]) : 0;

            mysql_free_result(result);
            mysql_close(mysql_);

            return true;
        }

        // 更新用户提交统计 - 每次提交后调用
        // accepted: true表示AC，false表示未AC
        bool UpdateUserStats(int user_id, bool accepted)
        {
            MYSQL *mysql_ = InitConnection();
            if (!mysql_)
                return false;

            char sql[1024];
            if (accepted)
            {
                // AC了，两个计数都加1
                snprintf(sql, sizeof(sql),
                         "UPDATE users SET total_submit=total_submit+1, "
                         "accepted_count=accepted_count+1 WHERE user_id=%d",
                         user_id);
            }
            else
            {
                // 没AC，只有总提交数加1
                snprintf(sql, sizeof(sql),
                         "UPDATE users SET total_submit=total_submit+1 WHERE user_id=%d",
                         user_id);
            }

            bool ret = mysql_query(mysql_, sql) == 0;
            mysql_close(mysql_);
            return ret;
        }

        // 获取排行榜 - 按AC数降序，AC数相同按提交数升序
        // 默认获取前100名
        // 获取到的排序好的user结果,通过输出型参数ranking带出
        bool GetRanking(std::vector<User> &ranking, int limit = 100)
        {
            MYSQL *mysql_ = InitConnection();
            if (!mysql_)
                return false;

            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "SELECT user_id, username, email, role, total_submit, accepted_count "
                     "FROM users ORDER BY accepted_count DESC, total_submit ASC LIMIT %d",
                     limit);

            if (mysql_query(mysql_, sql) != 0)
            {
                mysql_close(mysql_);
                return false;
            }

            MYSQL_RES *result = mysql_store_result(mysql_);
            if (result == nullptr)
            {
                mysql_close(mysql_);

                return false;
            }

            // 遍历结果集
            MYSQL_ROW row;
            while ((row = mysql_fetch_row(result)) != nullptr)
            {
                User user;
                user.user_id = atoi(row[0]);
                user.username = row[1];
                user.email = row[2] ? row[2] : "";
                user.role = row[3];
                user.total_submit = atoi(row[4]);
                user.accepted_count = atoi(row[5]);
                ranking.push_back(user);
            }

            mysql_free_result(result);
            mysql_close(mysql_);

            return true;
        }

        // 获取用户的提交历史:近50条
        bool GetUserSubmissions(int user_id, std::vector<Submission> &submissions)
        {
            MYSQL *mysql_ = InitConnection();

            if (!mysql_)
                return false;

            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "SELECT submission_id, user_id, question_number, status, submit_time "
                     "FROM submissions WHERE user_id=%d ORDER BY submit_time DESC LIMIT 50",
                     user_id);
            if (mysql_query(mysql_, sql) != 0)
            {
                mysql_close(mysql_);
                return false;
            }

            MYSQL_RES *result = mysql_store_result(mysql_);
            if (result == nullptr)
            {
                mysql_close(mysql_);

                return false;
            }

            MYSQL_ROW row;
            while ((row = mysql_fetch_row(result)) != nullptr)
            {
                Submission sub;
                sub.submission_id = atoi(row[0]);
                sub.user_id = atoi(row[1]);
                sub.question_number = row[2];
                sub.status = atoi(row[3]);
                sub.submit_time = row[4];
                submissions.push_back(sub);
            }

            mysql_free_result(result);
            mysql_close(mysql_);

            return true;
        }

        // 记录用户提交 - 在判题时调用
        bool RecordSubmission(int user_id, const std::string &question_number, int status)
        {
            MYSQL *mysql_ = InitConnection();

            if (!mysql_)
                return false;

            char sql[1024];
            snprintf(sql, sizeof(sql),
                     "INSERT INTO submissions (user_id, question_number, status, submit_time) "
                     "VALUES (%d, '%s', %d, NOW())",
                     user_id, question_number.c_str(), status); // 此处是submission_id自动增长
            bool ret = mysql_query(mysql_, sql) == 0;
            mysql_close(mysql_);
            return ret;
        }
    };
}
